{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Create a SageMaker MLOps Project for Pipelines\n",
    "Automatically run pipelines when code changes using Amazon SageMaker Projects\n",
    "\n",
    "Note:  This requires that you have enabled products within SageMaker Studio\n",
    "\n",
    "![](../img/enable-service-catalog-portfolio-for-studio.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import sagemaker\n",
    "import logging\n",
    "import boto3\n",
    "import sagemaker\n",
    "import pandas as pd\n",
    "from pprint import pprint\n",
    "\n",
    "sess = sagemaker.Session()\n",
    "bucket = sess.default_bucket()\n",
    "role = sagemaker.get_execution_role()\n",
    "region = boto3.Session().region_name\n",
    "\n",
    "sm = boto3.Session().client(service_name=\"sagemaker\", region_name=region)\n",
    "sc = boto3.Session().client(service_name=\"servicecatalog\", region_name=region)\n",
    "sts = boto3.Session().client(service_name=\"sts\", region_name=region)\n",
    "iam = boto3.Session().client(service_name=\"iam\", region_name=region)\n",
    "codepipeline = boto3.Session().client(\"codepipeline\", region_name=region)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "search_response = sc.search_products(\n",
    "    Filters={\"FullTextSearch\": [\"MLOps template for model building, training, and deployment\"]}\n",
    ")\n",
    "\n",
    "sagemaker_pipeline_product_id = search_response[\"ProductViewSummaries\"][0][\"ProductId\"]\n",
    "print(sagemaker_pipeline_product_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "describe_response = sc.describe_product(Id=sagemaker_pipeline_product_id)\n",
    "\n",
    "sagemaker_pipeline_product_provisioning_artifact_id = describe_response[\"ProvisioningArtifacts\"][-1][\"Id\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(sagemaker_pipeline_product_provisioning_artifact_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Create a SageMaker Project\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "timestamp = int(time.time())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sagemaker_project_name = \"dsoaws-{}\".format(timestamp)\n",
    "\n",
    "create_response = sm.create_project(\n",
    "    ProjectName=sagemaker_project_name,\n",
    "    ProjectDescription=\"dsoaws-{}\".format(timestamp),\n",
    "    ServiceCatalogProvisioningDetails={\n",
    "        \"ProductId\": sagemaker_pipeline_product_id,\n",
    "        \"ProvisioningArtifactId\": sagemaker_pipeline_product_provisioning_artifact_id,\n",
    "    },\n",
    ")\n",
    "\n",
    "sagemaker_project_id = create_response[\"ProjectId\"]\n",
    "sagemaker_project_arn = create_response[\"ProjectArn\"]\n",
    "\n",
    "print(\"Project ID {}\".format(sagemaker_project_id))\n",
    "print(\"Project ARN {}\".format(sagemaker_project_arn))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sagemaker_project_name_and_id = \"{}-{}\".format(sagemaker_project_name, sagemaker_project_id)\n",
    "\n",
    "print(\"Combined Project ID and ARN combined: {}\".format(sagemaker_project_name_and_id))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait for the Project to be Created_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "import time\n",
    "\n",
    "try:\n",
    "    describe_project_response = sm.describe_project(ProjectName=sagemaker_project_name)\n",
    "    project_status = describe_project_response[\"ProjectStatus\"]\n",
    "    print(\"Creating Project...\")\n",
    "\n",
    "    while project_status in [\"Pending\", \"CreateInProgress\"]:\n",
    "        print(\"Please wait...\")\n",
    "        time.sleep(30)\n",
    "        describe_project_response = sm.describe_project(ProjectName=sagemaker_project_name)\n",
    "        project_status = describe_project_response[\"ProjectStatus\"]\n",
    "        print(\"Project status: {}\".format(project_status))\n",
    "\n",
    "    if project_status == \"CreateCompleted\":\n",
    "        print(\"Project {}\".format(project_status))\n",
    "\n",
    "    else:\n",
    "        print(\"Project status: {}\".format(project_status))\n",
    "        raise Exception(\"Project not created.\")\n",
    "\n",
    "except Exception as e:\n",
    "    print(e)\n",
    "\n",
    "print(describe_project_response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait for Project to be Created ^^ Above ^^_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Attach IAM Policies for FeatureStore \n",
    "This is the role used by Code Build when it starts the pipeline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sc_role_name = \"AmazonSageMakerServiceCatalogProductsUseRole\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "account_id = sts.get_caller_identity()[\"Account\"]\n",
    "print(account_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "response = iam.attach_role_policy(RoleName=sc_role_name, PolicyArn=\"arn:aws:iam::aws:policy/AmazonSageMakerFullAccess\")\n",
    "\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "response = iam.attach_role_policy(\n",
    "    RoleName=sc_role_name, PolicyArn=\"arn:aws:iam::aws:policy/AmazonSageMakerFeatureStoreAccess\"\n",
    ")\n",
    "\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "response = iam.attach_role_policy(RoleName=sc_role_name, PolicyArn=\"arn:aws:iam::aws:policy/IAMFullAccess\")\n",
    "\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Stop the `Abalone` Sample Pipeline that Ships with SageMaker Pipelines\n",
    "The sample \"abalone\" pipeline starts automatically when we create the project.  We want to stop this pipeline to release these resources and use them for our own pipeline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sample_abalone_pipeline_execution_arn = sm.list_pipeline_executions(PipelineName=sagemaker_project_name_and_id)[\"PipelineExecutionSummaries\"][0][\"PipelineExecutionArn\"]\n",
    "\n",
    "print(sample_abalone_pipeline_execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sm.stop_pipeline_execution(PipelineExecutionArn=sample_abalone_pipeline_execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "try:\n",
    "    describe_pipeline_execution_response = sm.describe_pipeline_execution(\n",
    "        PipelineExecutionArn=sample_abalone_pipeline_execution_arn\n",
    "    )\n",
    "    pipeline_execution_status = describe_pipeline_execution_response[\"PipelineExecutionStatus\"]\n",
    "\n",
    "    while pipeline_execution_status not in [\"Stopped\", \"Failed\"]:\n",
    "        print(\"Please wait...\")\n",
    "        time.sleep(30)\n",
    "        describe_pipeline_execution_response = sm.describe_pipeline_execution(\n",
    "            PipelineExecutionArn=sample_abalone_pipeline_execution_arn\n",
    "        )\n",
    "        pipeline_execution_status = describe_pipeline_execution_response[\"PipelineExecutionStatus\"]\n",
    "        print(\"Pipeline execution status: {}\".format(pipeline_execution_status))\n",
    "\n",
    "    if pipeline_execution_status in [\"Stopped\", \"Failed\"]:\n",
    "        print(\"Pipeline execution status {}\".format(pipeline_execution_status))\n",
    "    else:\n",
    "        print(\"Pipeline execution status: {}\".format(pipeline_execution_status))\n",
    "        raise Exception(\"Pipeline execution not deleted.\")\n",
    "\n",
    "except Exception as e:\n",
    "    print(e)\n",
    "\n",
    "print(describe_pipeline_execution_response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sm.delete_pipeline(PipelineName=sagemaker_project_name_and_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Clone the MLOps Repositories in AWS CodeCommit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "sm_studio_root_path = \"/root/\"\n",
    "sm_notebooks_root_path = \"/home/ec2-user/SageMaker/\"\n",
    "\n",
    "root_path = sm_notebooks_root_path if os.path.isdir(sm_notebooks_root_path) else sm_studio_root_path\n",
    "\n",
    "print(root_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(region)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "code_commit_repo1 = \"https://git-codecommit.{}.amazonaws.com/v1/repos/sagemaker-{}-modelbuild\".format(\n",
    "    region, sagemaker_project_name_and_id\n",
    ")\n",
    "print(code_commit_repo1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sagemaker_mlops_build_code = \"{}{}/sagemaker-{}-modelbuild\".format(\n",
    "    root_path, sagemaker_project_name_and_id, sagemaker_project_name_and_id\n",
    ")\n",
    "print(sagemaker_mlops_build_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "code_commit_repo2 = \"https://git-codecommit.{}.amazonaws.com/v1/repos/sagemaker-{}-modeldeploy\".format(\n",
    "    region, sagemaker_project_name_and_id\n",
    ")\n",
    "print(code_commit_repo2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sagemaker_mlops_deploy_code = \"{}{}/sagemaker-{}-modeldeploy\".format(\n",
    "    root_path, sagemaker_project_name_and_id, sagemaker_project_name_and_id\n",
    ")\n",
    "print(sagemaker_mlops_deploy_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!git config --global credential.helper '!aws codecommit credential-helper $@'\n",
    "!git config --global credential.UseHttpPath true"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!git clone $code_commit_repo1 $sagemaker_mlops_build_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!git clone $code_commit_repo2 $sagemaker_mlops_deploy_code"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Remove Sample `Abalone` Example Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm -rf $sagemaker_mlops_build_code/pipelines/abalone"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Copy Workshop Code Into Local Project Folders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "workshop_project_build_code = \"{}workshop/10_pipeline/sagemaker_mlops/sagemaker-project-modelbuild\".format(root_path)\n",
    "print(workshop_project_build_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "workshop_project_deploy_code = \"{}workshop/10_pipeline/sagemaker_mlops/sagemaker-project-modeldeploy\".format(root_path)\n",
    "print(workshop_project_deploy_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cp -R $workshop_project_build_code/* $sagemaker_mlops_build_code/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cp -R $workshop_project_deploy_code/* $sagemaker_mlops_deploy_code/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Commit New Code "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(sagemaker_mlops_build_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cd $sagemaker_mlops_build_code; git status; git add --all .; git commit -m \"Data Science on AWS\"; git push"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "!cd $sagemaker_mlops_deploy_code; git status; git add --all .; git commit -m \"Data Science on AWS\"; git push"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Store the Variables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%store sagemaker_mlops_build_code\n",
    "%store sagemaker_mlops_deploy_code\n",
    "%store sagemaker_project_name\n",
    "%store sagemaker_project_id\n",
    "%store sagemaker_project_name_and_id\n",
    "%store sagemaker_project_arn\n",
    "%store sagemaker_pipeline_product_id\n",
    "%store sagemaker_pipeline_product_provisioning_artifact_id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls -al $sagemaker_mlops_build_code/pipelines/dsoaws/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "!pygmentize $sagemaker_mlops_build_code/pipelines/dsoaws/pipeline.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wait for Pipeline Execution to Start\n",
    "Now that we have committed code, our pipeline will start.  Let's wait for the pipeline to start.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "import time\n",
    "from pprint import pprint\n",
    "\n",
    "while True:\n",
    "    try:\n",
    "        print(\"Listing executions for our pipeline...\")\n",
    "        list_executions_response = sm.list_pipeline_executions(PipelineName=sagemaker_project_name_and_id)[\n",
    "            \"PipelineExecutionSummaries\"\n",
    "        ]\n",
    "        break\n",
    "    except Exception as e:\n",
    "        print(\"Please wait...\")\n",
    "        time.sleep(30)\n",
    "\n",
    "pprint(list_executions_response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "build_pipeline_name = \"sagemaker-{}-modelbuild\".format(sagemaker_project_name_and_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Check <a target=\"blank\" href=\"https://console.aws.amazon.com/codesuite/codepipeline/pipelines/{}/view?region={}\">ModelBuild</a> Pipeline</b>'.format(\n",
    "            build_pipeline_name, region\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wait For Pipeline Execution To Complete"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "import time\n",
    "from pprint import pprint\n",
    "\n",
    "executions_response = sm.list_pipeline_executions(PipelineName=sagemaker_project_name_and_id)[\n",
    "    \"PipelineExecutionSummaries\"\n",
    "]\n",
    "pipeline_execution_status = executions_response[0][\"PipelineExecutionStatus\"]\n",
    "print(pipeline_execution_status)\n",
    "\n",
    "while pipeline_execution_status == \"Executing\":\n",
    "    try:\n",
    "        executions_response = sm.list_pipeline_executions(PipelineName=sagemaker_project_name_and_id)[\n",
    "            \"PipelineExecutionSummaries\"\n",
    "        ]\n",
    "        pipeline_execution_status = executions_response[0][\"PipelineExecutionStatus\"]\n",
    "    #        print('Executions for our pipeline...')\n",
    "    #        print(pipeline_execution_status)\n",
    "    except Exception as e:\n",
    "        print(\"Please wait...\")\n",
    "        time.sleep(30)\n",
    "\n",
    "pprint(executions_response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait for the Pipeline Execution ^^ Above ^^ to Complete_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# List Pipeline Execution Steps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pipeline_execution_status = executions_response[0][\"PipelineExecutionStatus\"]\n",
    "print(pipeline_execution_status)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pipeline_execution_arn = executions_response[0][\"PipelineExecutionArn\"]\n",
    "print(pipeline_execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pd.set_option(\"max_colwidth\", 1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pprint import pprint\n",
    "\n",
    "steps = sm.list_pipeline_execution_steps(PipelineExecutionArn=pipeline_execution_arn)\n",
    "\n",
    "pprint(steps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "from sagemaker.lineage.visualizer import LineageTableVisualizer\n",
    "\n",
    "viz = LineageTableVisualizer(sagemaker.session.Session())\n",
    "\n",
    "for execution_step in reversed(steps[\"PipelineExecutionSteps\"]):\n",
    "    print(execution_step)\n",
    "    # We are doing this because there appears to be a bug of this LineageTableVisualizer handling the Processing Step\n",
    "    if execution_step[\"StepName\"] == \"Processing\":\n",
    "        processing_job_name = execution_step[\"Metadata\"][\"ProcessingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(processing_job_name)\n",
    "        display(viz.show(processing_job_name=processing_job_name))\n",
    "    elif execution_step[\"StepName\"] == \"Train\":\n",
    "        training_job_name = execution_step[\"Metadata\"][\"TrainingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(training_job_name)\n",
    "        display(viz.show(training_job_name=training_job_name))\n",
    "    else:\n",
    "        display(viz.show(pipeline_execution_step=execution_step))\n",
    "        time.sleep(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Approve the Registered Model for Staging\n",
    "The pipeline that was executed created a Model Package version within the specified Model Package Group. Of particular note, the registration of the model/creation of the Model Package was done so with approval status as `PendingManualApproval`.\n",
    "\n",
    "Notes:  \n",
    "* You can do this within SageMaker Studio, as well.  However, we are approving programmatically here in this example.\n",
    "* This approval is only for Staging.  For Production, you must go through the CodePipeline (deep link is below.)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "import time\n",
    "from pprint import pprint\n",
    "\n",
    "while True:\n",
    "    try:\n",
    "        print(\"Executions for our pipeline...\")\n",
    "        list_model_packages_response = sm.list_model_packages(ModelPackageGroupName=sagemaker_project_name_and_id)\n",
    "        break\n",
    "    except Exception as e:\n",
    "        print(\"Please wait...\")\n",
    "        time.sleep(30)\n",
    "\n",
    "pprint(list_model_packages_response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "time.sleep(30)\n",
    "\n",
    "model_package_arn = list_model_packages_response[\"ModelPackageSummaryList\"][0][\"ModelPackageArn\"]\n",
    "print(model_package_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_package_update_response = sm.update_model_package(\n",
    "    ModelPackageArn=model_package_arn,\n",
    "    ModelApprovalStatus=\"Approved\",\n",
    ")\n",
    "\n",
    "print(model_package_update_response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "time.sleep(30)\n",
    "\n",
    "model_name = sm.list_models()[\"Models\"][0][\"ModelName\"]\n",
    "print(model_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Review <a target=\"blank\" href=\"https://console.aws.amazon.com/sagemaker/home?region={}#/models/{}\">Model</a></b>'.format(\n",
    "            region, model_name\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "deploy_pipeline_name = \"sagemaker-{}-modeldeploy\".format(sagemaker_project_name_and_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Check <a target=\"blank\" href=\"https://console.aws.amazon.com/codesuite/codepipeline/pipelines/{}/view?region={}\">ModelDeploy</a> Pipeline</b>'.format(\n",
    "            deploy_pipeline_name, region\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "staging_endpoint_name = \"{}-staging\".format(sagemaker_project_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Review <a target=\"blank\" href=\"https://console.aws.amazon.com/sagemaker/home?region={}#/endpoints/{}\">SageMaker Staging REST Endpoint</a></b>'.format(\n",
    "            region, staging_endpoint_name\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait Until the Staging Endpoint is Deployed_\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "while True:\n",
    "    try:\n",
    "        waiter = sm.get_waiter(\"endpoint_in_service\")\n",
    "        print(\"Waiting for staging endpoint to be in `InService`...\")\n",
    "        waiter.wait(EndpointName=staging_endpoint_name)\n",
    "        break\n",
    "    except:\n",
    "        print(\"Waiting for staging endpoint to be in `Creating`...\")\n",
    "        time.sleep(30)\n",
    "\n",
    "print(\"Staging endpoint deployed.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait Until the ^^ Staging Endpoint ^^ is Deployed_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# List Artifact Lineage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pprint import pprint\n",
    "\n",
    "steps = sm.list_pipeline_execution_steps(PipelineExecutionArn=pipeline_execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "from sagemaker.lineage.visualizer import LineageTableVisualizer\n",
    "\n",
    "viz = LineageTableVisualizer(sagemaker.session.Session())\n",
    "\n",
    "for execution_step in reversed(steps[\"PipelineExecutionSteps\"]):\n",
    "    print(execution_step)\n",
    "    # We are doing this because there appears to be a bug of this LineageTableVisualizer handling the Processing Step\n",
    "    if execution_step[\"StepName\"] == \"Processing\":\n",
    "        processing_job_name = execution_step[\"Metadata\"][\"ProcessingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(processing_job_name)\n",
    "        display(viz.show(processing_job_name=processing_job_name))\n",
    "    elif execution_step[\"StepName\"] == \"Train\":\n",
    "        training_job_name = execution_step[\"Metadata\"][\"TrainingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(training_job_name)\n",
    "        display(viz.show(training_job_name=training_job_name))\n",
    "    else:\n",
    "        display(viz.show(pipeline_execution_step=execution_step))\n",
    "        time.sleep(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run A Sample Prediction in Staging"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from sagemaker.tensorflow.model import TensorFlowPredictor\n",
    "from sagemaker.serializers import JSONLinesSerializer\n",
    "from sagemaker.deserializers import JSONLinesDeserializer\n",
    "\n",
    "predictor = TensorFlowPredictor(\n",
    "    endpoint_name=staging_endpoint_name,\n",
    "    sagemaker_session=sess,\n",
    "    model_name=\"saved_model\",\n",
    "    model_version=0,\n",
    "    content_type=\"application/jsonlines\",\n",
    "    accept_type=\"application/jsonlines\",\n",
    "    serializer=JSONLinesSerializer(),\n",
    "    deserializer=JSONLinesDeserializer(),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "inputs = [{\"features\": [\"This is great!\"]}, {\"features\": [\"This is bad.\"]}]\n",
    "\n",
    "predicted_classes = predictor.predict(inputs)\n",
    "\n",
    "for predicted_class in predicted_classes:\n",
    "    print(\"Predicted star_rating: {}\".format(predicted_class))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deploy to Production"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Review <a target=\"blank\" href=\"https://console.aws.amazon.com/codesuite/codepipeline/pipelines/sagemaker-{}-modeldeploy/view?region={}\"> Deploy to Production </a> Pipeline</b> '.format(\n",
    "            sagemaker_project_name_and_id, region\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "stage_name = \"DeployStaging\"\n",
    "action_name = \"ApproveDeployment\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "time.sleep(60)\n",
    "\n",
    "stage_states = codepipeline.get_pipeline_state(name=deploy_pipeline_name)[\"stageStates\"]\n",
    "\n",
    "for stage_state in stage_states:\n",
    "\n",
    "    if stage_state[\"stageName\"] == stage_name:\n",
    "        for action_state in stage_state[\"actionStates\"]:\n",
    "            if action_state[\"actionName\"] == action_name:\n",
    "                token = action_state[\"latestExecution\"][\"token\"]\n",
    "\n",
    "print(token)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "response = codepipeline.put_approval_result(\n",
    "    pipelineName=deploy_pipeline_name,\n",
    "    stageName=stage_name,\n",
    "    actionName=action_name,\n",
    "    result={\"summary\": \"Approve from Staging to Production\", \"status\": \"Approved\"},\n",
    "    token=token,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Get the Production Endpoint Name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "time.sleep(30)\n",
    "\n",
    "production_endpoint_name = \"{}-prod\".format(sagemaker_project_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "\n",
    "display(\n",
    "    HTML(\n",
    "        '<b>Review <a target=\"blank\" href=\"https://console.aws.amazon.com/sagemaker/home?region={}#/endpoints/{}\">SageMaker Production REST Endpoint</a></b>'.format(\n",
    "            region, production_endpoint_name\n",
    "        )\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait Until the Production Endpoint is Deployed_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "while True:\n",
    "    try:\n",
    "        waiter = sm.get_waiter(\"endpoint_in_service\")\n",
    "        print(\"Waiting for production endpoint to be in `InService`...\")\n",
    "        waiter.wait(EndpointName=production_endpoint_name)\n",
    "        break\n",
    "    except:\n",
    "        print(\"Waiting for production endpoint to be in `Creating`...\")\n",
    "        time.sleep(30)\n",
    "\n",
    "print(\"Production endpoint deployed.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# _Wait Until the ^^ Production Endpoint ^^ is Deployed_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from sagemaker.tensorflow.model import TensorFlowPredictor\n",
    "from sagemaker.serializers import JSONLinesSerializer\n",
    "from sagemaker.deserializers import JSONLinesDeserializer\n",
    "\n",
    "predictor = TensorFlowPredictor(\n",
    "    endpoint_name=production_endpoint_name,\n",
    "    sagemaker_session=sess,\n",
    "    model_name=\"saved_model\",\n",
    "    model_version=0,\n",
    "    content_type=\"application/jsonlines\",\n",
    "    accept_type=\"application/jsonlines\",\n",
    "    serializer=JSONLinesSerializer(),\n",
    "    deserializer=JSONLinesDeserializer(),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "inputs = [{\"features\": [\"This is great!\"]}, {\"features\": [\"This is bad.\"]}]\n",
    "\n",
    "predicted_classes = predictor.predict(inputs)\n",
    "\n",
    "for predicted_class in predicted_classes:\n",
    "    print(\"Predicted star_rating: {}\".format(predicted_class))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# List Artifact Lineage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pprint import pprint\n",
    "\n",
    "steps = sm.list_pipeline_execution_steps(PipelineExecutionArn=pipeline_execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "from sagemaker.lineage.visualizer import LineageTableVisualizer\n",
    "\n",
    "viz = LineageTableVisualizer(sagemaker.session.Session())\n",
    "\n",
    "for execution_step in reversed(steps[\"PipelineExecutionSteps\"]):\n",
    "    print(execution_step)\n",
    "    # We are doing this because there appears to be a bug of this LineageTableVisualizer handling the Processing Step\n",
    "    if execution_step[\"StepName\"] == \"Processing\":\n",
    "        processing_job_name = execution_step[\"Metadata\"][\"ProcessingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(processing_job_name)\n",
    "        display(viz.show(processing_job_name=processing_job_name))\n",
    "    elif execution_step[\"StepName\"] == \"Train\":\n",
    "        training_job_name = execution_step[\"Metadata\"][\"TrainingJob\"][\"Arn\"].split(\"/\")[-1]\n",
    "        print(training_job_name)\n",
    "        display(viz.show(training_job_name=training_job_name))\n",
    "    else:\n",
    "        display(viz.show(pipeline_execution_step=execution_step))\n",
    "        time.sleep(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Release Resources"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%html\n",
    "\n",
    "<p><b>Shutting down your kernel for this notebook to release resources.</b></p>\n",
    "<button class=\"sm-command-button\" data-commandlinker-command=\"kernelmenu:shutdown\" style=\"display:none;\">Shutdown Kernel</button>\n",
    "        \n",
    "<script>\n",
    "try {\n",
    "    els = document.getElementsByClassName(\"sm-command-button\");\n",
    "    els[0].click();\n",
    "}\n",
    "catch(err) {\n",
    "    // NoOp\n",
    "}    \n",
    "</script>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%javascript\n",
    "\n",
    "try {\n",
    "    Jupyter.notebook.save_checkpoint();\n",
    "    Jupyter.notebook.session.delete();\n",
    "}\n",
    "catch(err) {\n",
    "    // NoOp\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "instance_type": "ml.t3.medium",
  "kernelspec": {
   "display_name": "Python 3 (Data Science)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
